package com.gliese.bambook.service.news.impl;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.StringReader;
import java.util.List;
import java.util.Properties;

import org.apache.commons.httpclient.DefaultHttpMethodRetryHandler;
import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.HttpException;
import org.apache.commons.httpclient.HttpMethod;
import org.apache.commons.httpclient.HttpStatus;
import org.apache.commons.httpclient.methods.GetMethod;
import org.apache.commons.httpclient.params.HttpMethodParams;
import org.apache.commons.lang.ClassUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.Node;
import org.dom4j.io.SAXReader;
import org.htmlparser.util.ParserException;
import org.springframework.beans.factory.InitializingBean;

import com.gliese.bambook.object.Snbc;
import com.gliese.bambook.service.news.interfaces.NewsAnalysisService;
import com.gliese.bambook.util.HtmlToXmlUtils;
import com.gliese.util.file.FileReaderHelper;

/**
 * get news from news.sina.com
 * 
 * @author hyvi
 * 
 */
public class SinaNewsAnalysisService implements InitializingBean,
		NewsAnalysisService {
	final Log log = LogFactory.getLog(SinaNewsAnalysisService.class);
	Properties properties = new Properties();

	@Override
	public Snbc analyzeNews(String newsUrl) {
		Snbc snbc = new Snbc();
		HttpClient httpClient = new HttpClient();
		HttpMethod httpMethod = new GetMethod(newsUrl);
		httpMethod.getParams().setParameter(HttpMethodParams.RETRY_HANDLER,
				new DefaultHttpMethodRetryHandler(3, false));
		try {
			int statusCode = httpClient.executeMethod(httpMethod);
			if (statusCode != HttpStatus.SC_OK) {
				log.error("Method failed: " + httpMethod.getStatusLine());
			}
			InputStream inputStream = httpMethod.getResponseBodyAsStream();
			BufferedReader br = new BufferedReader(new InputStreamReader(
					inputStream));
			StringBuilder httpSb = new StringBuilder();
			String inputLine;
			while ((inputLine = br.readLine()) != null) {
				httpSb.append(inputLine);
			}
			/**
			 * filter unnormal content ,such as "<!DOCTYPE ... > ,<../> <br>
			 * "
			 */
			String httpHtml = httpSb.toString();
			try {
				httpHtml = HtmlToXmlUtils.convertHtmlToXMLByLexer(httpHtml);
			} catch (ParserException pe) {
				throw new RuntimeException(pe);
			}

			/**
			 * xml analysis
			 */
			SAXReader saxReader = new SAXReader();
			Document document = saxReader.read(new StringReader(httpHtml));
			List<?> snbcTitleNode = document.selectNodes(properties.get(
					"snbcTitle").toString());
			snbc.setSnbcTitle(((Node) (snbcTitleNode.get(0))).getText());

			Element snbcContentElement = (Element) document
					.selectSingleNode(properties.get("snbcContext").toString());
			// process contexts such as image ,text.
			processContextForSinaNews(snbcContentElement,snbc);
			
			//date
			Element snbcDate =(Element)document.selectSingleNode(properties.get("date").toString());
			snbc.setDate(snbcDate!=null?snbcDate.getTextTrim():"No Public Date");
			//author
			Element snbcAuthor = (Element)document.selectSingleNode(properties.get("author").toString());
			snbc.setAuthor(snbcAuthor!=null?snbcAuthor.getTextTrim():"No Author");
			//url
			Element snbcUrl = (Element)document.selectSingleNode(properties.get("url").toString());
			snbc.setUrl(snbcUrl.getTextTrim());
			
		} catch (HttpException e) {
			log.error("Fatal Protocol violation: " + e.getMessage());
			if (log.isDebugEnabled()) {
				e.printStackTrace();
			}
		} catch (IOException e) {
			log.error("Fatal transport error : " + e.getMessage());
			if (log.isDebugEnabled()) {
				e.printStackTrace();
			}
		} catch (DocumentException e) {
			log.error("Fatal parsing error : " + e.getMessage());
			if (log.isDebugEnabled()) {
				e.printStackTrace();
			}
		} finally {
			httpMethod.releaseConnection();
		}
		return snbc;
	}
	
	/**
	 * process context , currently only for text.
	 * @param element
	 * @param snbc
	 */
	private void processContextForSinaNews(Element element,Snbc snbc){
		List<?> list = element.selectNodes("p");
		for(Object o: list){
			Element elementNode = (Element)o;
			snbc.getSnbcContextItems().add(elementNode.getStringValue().trim());
		}
	}
	@Override
	public void afterPropertiesSet() throws Exception {
		String fileName = ClassUtils
				.getShortClassName(SinaNewsAnalysisService.class)
				+ "_rule.properties";

		InputStream is = FileReaderHelper.readResourceByURL(fileName);
		if (is == null) {
			log.error("File not exist : " + fileName);
			return;
		}
		properties.load(is);
		// check configuration

		if (properties.get("snbcTitle") == null) {
			log.error("snbcTitle  not configuration");
		}
		if (properties.get("snbcContext") == null) {
			log.error("snbcContext not configuration");
		}
	}
}
